/**
 * Model 类 - 负责数据模型定义和验证
 * 
 * @class Model
 */

import { ObjectId } from './Utils';

// 存储所有已定义的模型
const models = new Map();

class Model {
  /**
   * 构造函数
   * @param {string} name - 模型名称
   * @param {Object} schema - 模型架构
   */
  constructor(name, schema) {
    this.name = name;
    this.schema = schema;
    this.primaryKey = this._findPrimaryKey();
    this.defaultValues = this._extractDefaultValues();
  }
  
  /**
   * 查找主键字段
   * @private
   * @returns {string|null} 主键字段名
   */
  _findPrimaryKey() {
    for (const [field, definition] of Object.entries(this.schema)) {
      if (typeof definition === 'object' && definition.primaryKey) {
        return field;
      }
    }
    return null;
  }
  
  /**
   * 提取默认值
   * @private
   * @returns {Object} 默认值对象
   */
  _extractDefaultValues() {
    const defaults = {};
    
    for (const [field, definition] of Object.entries(this.schema)) {
      if (typeof definition === 'object' && 'default' in definition) {
        defaults[field] = definition.default;
      }
    }
    
    return defaults;
  }
  
  /**
   * 验证文档数据
   * @param {Object} data - 文档数据
   * @returns {Object} 验证后的文档数据
   */
  validate(data) {
    const validatedData = { ...data };
    
    // 应用默认值
    for (const [field, defaultValue] of Object.entries(this.defaultValues)) {
      if (!(field in validatedData)) {
        validatedData[field] = typeof defaultValue === 'function' 
          ? defaultValue() 
          : defaultValue;
      }
    }
    
    // 验证字段类型
    for (const [field, definition] of Object.entries(this.schema)) {
      if (field in validatedData) {
        this._validateField(field, validatedData[field], definition);
      }
    }
    
    // 确保主键存在（如果定义了主键）
    if (this.primaryKey && !(this.primaryKey in validatedData)) {
      validatedData[this.primaryKey] = new ObjectId().toString();
    }
    
    return validatedData;
  }
  
  /**
   * 验证单个字段
   * @private
   * @param {string} field - 字段名
   * @param {any} value - 字段值
   * @param {any} definition - 字段定义
   */
  _validateField(field, value, definition) {
    let expectedType;
    let isRef = false;
    
    if (typeof definition === 'object') {
      expectedType = definition.type;
      isRef = definition.ref || false;
    } else {
      expectedType = definition;
    }
    
    // 引用类型检查
    if (isRef && typeof expectedType === 'string') {
      const refModel = Model.getModel(expectedType);
      if (!refModel) {
        throw new Error(`Referenced model '${expectedType}' is not defined`);
      }
      
      // 引用类型的值应该是一个ID或者包含ID的对象
      if (typeof value !== 'string' && !(value && typeof value === 'object' && refModel.primaryKey in value)) {
        throw new Error(`Field '${field}' must be a reference to '${expectedType}' (string ID or object with ID)`);
      }
      return;
    }
    
    // 原生类型检查
    if (expectedType === String && typeof value !== 'string') {
      throw new Error(`Field '${field}' must be a string`);
    } else if (expectedType === Number && typeof value !== 'number') {
      throw new Error(`Field '${field}' must be a number`);
    } else if (expectedType === Boolean && typeof value !== 'boolean') {
      throw new Error(`Field '${field}' must be a boolean`);
    } else if (expectedType === Array && !Array.isArray(value)) {
      throw new Error(`Field '${field}' must be an array`);
    } else if (expectedType === Object && typeof value !== 'object' || value === null) {
      throw new Error(`Field '${field}' must be an object`);
    }
  }
  
  /**
   * 创建新的文档实例
   * @param {Object} data - 文档数据
   * @returns {Object} 文档实例
   */
  create(data = {}) {
    const validatedData = this.validate(data);
    
    // 创建文档对象，添加modelName属性以便识别
    const doc = {
      ...validatedData,
      collectionName: this.name,
      // 添加保存方法
      save: async function(db) {
        return await db.save(this);
      }
    };
    
    return doc;
  }
  
  /**
   * 从JSON数据创建模型实例
   * @param {Object} json - JSON数据
   * @returns {Object} 模型实例
   */
  fromJSON(json) {
    const doc = { ...json };
    
    // 添加modelName属性
    doc.collectionName = this.name;
    
    // 添加保存方法
    doc.save = async function(db) {
      return await db.save(this);
    };
    
    return doc;
  }
  
  /**
   * 获取模型的架构信息
   * @returns {Object} 架构信息
   */
  getSchemaInfo() {
    return {
      name: this.name,
      fields: this.schema,
      primaryKey: this.primaryKey
    };
  }
  
  /**
   * 静态方法：定义新模型
   * @static
   * @param {string} name - 模型名称
   * @param {Object} schema - 模型架构
   * @returns {Model} 模型实例
   */
  static define(name, schema) {
    if (!name || typeof name !== 'string') {
      throw new Error('Model name must be a non-empty string');
    }
    
    if (!schema || typeof schema !== 'object') {
      throw new Error('Schema must be a non-empty object');
    }
    
    const model = new Model(name, schema);
    models.set(name, model);
    
    return model;
  }
  
  /**
   * 静态方法：获取已定义的模型
   * @static
   * @param {string} name - 模型名称
   * @returns {Model|null} 模型实例或null
   */
  static getModel(name) {
    return models.get(name) || null;
  }
  
  /**
   * 静态方法：获取所有已定义的模型
   * @static
   * @returns {Array<Model>} 模型实例数组
   */
  static getAllModels() {
    return Array.from(models.values());
  }
  
  /**
   * 静态方法：检查模型是否已定义
   * @static
   * @param {string} name - 模型名称
   * @returns {boolean} 是否已定义
   */
  static isDefined(name) {
    return models.has(name);
  }
}

export default Model;